Skip to content

feat(types)!: mirror eight ObjectViewSchema keys (three by spec reference) and retire viewTabBar (objectui#7779) - #7922

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-7779-object-view-unmirrored-keys
Sep 6, 2026
Merged

feat(types)!: mirror eight ObjectViewSchema keys (three by spec reference) and retire viewTabBar (objectui#7779)#7922
os-zhuang merged 2 commits into
mainfrom
claude/issue-7779-object-view-unmirrored-keys

Conversation

@os-justin

Copy link
Copy Markdown
Collaborator

Fixes #7779

What this PR does

ObjectViewSchema's TypeScript face declared ten keys its Zod mirror never did (the UnmirroredDeclared entry objectui#7279 re-derived), so a document authoring any of them passed the validator unexamined through BaseSchema's passthrough while the published type invited the author to write it. Under the maintainer's ruling B on the card (2026-09-06, verbatim 「第二批(4 项,契约形状族) 帮我处理,全部同意」; record 5556357004) — liveness first, then mirror-or-retire per key — nine of the ten are dispositioned here and the tenth (listViews) stays in the ledger on the ruling's own fallback clause, with its measurement.

Read on origin/main 6a9ee323 (the branch base). The seat's premise at fa7d66c4 re-verified on it: objectql.zod.ts:196, the ten declarations at objectql.ts:1804:1922, ledger rows :702 / :864 / :1437 / :1604 / :1855 / :2866:2867, all as stated; every reading below is bound to the ObjectViewSchema block, never to a name match (navigation and searchableFields also live on other interfaces in the same file).

Per key

key disposition census on the object-view node renderer — packages/plugin-view/src/ObjectView.tsx, registered by plugin-view/src/index.tsx
navigation mirrored BY REFERENCE — SpecListViewSchema.shape.navigation read :773 schema.navigation; :1817
searchableFields by reference — SpecListViewSchema.shape.searchableFields read :1820
filterableFields by reference — SpecListViewSchema.shape.filterableFields read :1821
allowCreateView by reference to the sibling ViewSwitcherSchema.shape.allowCreateView (views.zod.ts) read :1134 — forwarded verbatim into the view-switcher node the renderer composes; ViewSwitcher.tsx:276 reads it
viewActions by reference to ViewSwitcherSchema.shape.viewActions read :1135; ViewSwitcher.tsx:254:256
defaultViewType local literal — the declaration's seven-value enum read :769 schema.defaultViewType OR 'grid'
defaultListView local literal — string read :701:702 namedListViews?.[schema.defaultListView]
showViewSwitcher local literal — boolean read :1910 schema.showViewSwitcher === true
viewTabBar RETIRED — ?: never on the TS face, retirementTombstone() on the mirror ZERO reads on the node; repo-wide the key appears in no source file outside @object-ui/types (two doc tables listed it as authorable, corrected here). ViewTabBarConfig reaches the tab bar only as ViewTabBar's config PROP, passed by app-shell (views/ObjectView.tsx:2825); plugin-view's own ObjectView renders no tab bar (ADR-0053). The 2026-07 audit had measured it "dead since introduction"
listViews UNCHANGED — stays ledgered read :698, plus seven NamedListView members — see below

Positive controls of the same schema.KEY query: objectName and layout (read); viewTabBar and the never-declared viewSwitcherPosition (not read). The pin derives this set off disk, so each zero is a reading.

Why allowCreateView / viewActions are sibling slots rather than restated literals: the renderer hands both to the switcher node unchanged, the sibling mirror already spells the identical shape (z.enum(['share', 'settings', 'duplicate', 'delete']) plus optional icon), and one object for one key is what stops the two from drifting. defaultViewType is deliberately the declaration's seven values, not the spec's nine-value view-kind enum: chart / tree are host-composition-only on this node (objectui#5321) and NamedListView.type spells the same seven.

Spec-side readings, through the installed pin

@objectstack/spec@17.2.0, ui entry, measured from this worktree — 117 exported object schemas walked; control keys objectName 9 hits, columns 15, navigation 5, listViews 1; each of the six local keys 0 hits:

  • ListViewSchema.navigation and ObjectListViewSchema.navigation: optional object (NavigationConfigSchema: mode defaulting to page, view, preventNavigation, openNewTab, size, width; strict, an unknown key is refused). { view: 'summary_view' } parses with mode defaulted; a bare string is refused.
  • searchableFields and filterableFields on both view faces: optional array of string; the spec's own description of filterableFields is "Legacy shorthand for userFilters.fields — bare field names enabled for end-user filtering. Prefer userFilters".
  • ViewSchema.listViews: optional record whose VALUE is ObjectListViewSchema by identity — strict (catchall never), columns its only required key (a union), type a nine-value enum defaulting to grid.

listViews — measured, and left in the ledger on the ruling's stop clause

What the two value types admit, and what the readers accept:

  • The renderer reads seven NamedListView members off a named view — label, type, columns, filter, sort, options, data (derived off disk and pinned). NamedListView declares about 52 members (objectql.ts:1957:2134).
  • The spec value (ObjectListViewSchema) accepts the schema-catalog example ({ label, columns }) but REFUSES: the README / mdx form { label: 'All Users' } (at columns); a type plus filter view with no columns (at columns); content/docs/api/schema-reference.md's ObjectQL tuple filter [["owner", "=", "..."]] (at filter.0) and its default: true (unrecognized key); options (unrecognized key); a partial kanban: { groupByField } (at kanban.columns).
  • The writers disagree as well: the README and mdx author the local shape; schema-reference.md authors tuple filters; app-shell's ViewPreview.tsx:113 spreads a spec-shaped view body into listViews.

So mirroring the spec value by reference loses documented behaviour, and mirroring the local NamedListView key-for-key enforces about 45 members the renderer never reads — the "enforced dead key" ruling B refused for the six local keys. That is the ruling's stop condition for this key, and its own instruction is followed: the other spec-modelled keys are mirrored, listViews stays in the ledger with the measurement (pinned against the SPEC schema, so a spec relaxation or a renderer change re-takes it instead of remembering it). z.any() is not used anywhere. The value-type decision goes to the maintainer in the report's open questions with the four-axis analysis.

Ledger and pins

  • zod-mirror-parity.test.ts: the ObjectViewSchema entry shrinks 10 → 1 (listViews); SPEC_DERIVED_PAIRS gains the pair by a real code reference (the objectui#6705 scanner now sees SpecListViewSchema.shape.* in the initializer), so the split re-derives the entry into the SPEC-DERIVED half; header figures move 14 / 96 → 14 / 87 and 1 / 2 + 13 / 94 → 2 / 3 + 12 / 84, each with its history sentence (the PR test(types): re-derive ObjectViewSchema's side of the #6058 split as LOCAL and pin the header counts (objectui#7279) #7776 / PR feat(types)!: retire the legacy ActionSchema onSuccess/onFailure callback pair and delete ActionCallback (objectui#7068) #7832 shape). The objectui#7279 pin reads them off the header and agrees.
  • object-view-spec-parity.test.ts — a seventh file, not on the dispatch's list, moved by a gate: its TS_ONLY_BACKLOG "may shrink, never grow" pin held exactly these ten keys. It shrinks to listViews plus onNavigate; the audit figures move 11 / 13 → 20 / 22 with the arithmetic shown; the three spec-counterpart notes now read DONE.
  • New pin object-view-unmirrored-keys-7779.test.ts (52 tests): reads derived off disk with controls; membership on the mirror's own .shape; identity against the spec slots and the sibling slots; per mirrored key, accepted-and-survives plus a wrong-typed refusal AT the key (12 refusal probes, direct and through the union door); the tombstone on both faces (message, code invalid_type, describe equals message, TS never at the type level plus @ts-expect-error); the listViews measurement against the spec; neighbour and passthrough controls; the two doc tables.
  • Docs: the packages/plugin-view/README.md and content/docs/plugins/plugin-view.mdx import tables no longer teach viewTabBar as a node key — the only two pages that did; the diff moves zero fenced snippets.
  • Changeset: @object-ui/types minor, "Breaking for authored metadata" opening, every key and its disposition named.

Gates — exit captured before any pipe, verdict lines quoted, heavy runs under the shared verify lock

Taken on e9f86194; the ratchet family re-run on the merged head 94e7ac47 (origin/main f5d2acc3 merged in; main moved nothing under packages/types since the base):

  • pnpm --filter @object-ui/types buildVERDICT command-exit 0 (dist completeness: 124 emitted files verified)
  • pnpm exec vitest run --maxWorkers=2 packages/types/Test Files 129 passed (129), Tests 2388 passed (2388), VERDICT command-exit 0; re-run at 94e7ac47: the same figures
  • pnpm --filter @object-ui/types type-check (tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json) — VERDICT command-exit 0; tsc -p tsconfig.test.json --listFiles lists the new pin (1 hit); re-run at 94e7ac47: green in the same verdict
  • consumer type-checks, DOWNSTREAM direction, against the rebuilt dist (their tsconfigs drop the root paths, so @object-ui/types resolves to dist/*.d.ts): pnpm --workspace-concurrency=2 --filter @object-ui/plugin-list --filter @object-ui/plugin-view --filter @object-ui/app-shell type-check after building each dependency closure — all three echo type-check$ tsc --noEmit && tsc -p tsconfig.test.json and Done, VERDICT command-exit 0
  • reverse verification of the cross-package type change: a throwaway probe compiled standalone against the dist, authoring viewTabBar: { showAddButton: true } and defaultViewType: 'tree' — exactly two TS2322 at those two lines (not assignable to type 'undefined'; '"tree"' is not assignable to …'"kanban" | "grid" | …'), the eight-key literal beside them clean, --listFiles reading packages/types/dist/objectql.d.ts with 0 src reads; probe removed, tree clean
  • pnpm --filter @object-ui/types lint — 0 errors (274 pre-existing no-explicit-any warnings, none in the touched regions)
  • check-changeset-presence.mjs / -no-major / -fixed / -overwrite — all ✅; check-control-bytes.mjs ✅ (6396 tracked text files); pnpm check:spec-symbols ✅; check:doc-types ✅; check:doc-fences ✅; check:vi-mock-specifiers ✅; check:vi-mock-inherit ✅; check:shell-escape-residue ✅; check:unreferenced-sources
  • NOT MEASURED locally (a precondition, not a red): check:doc-snippets exits 2 PRECONDITION NOT MET (six unbuilt packages, none of them this PR's); check:readme-exports could not judge one plugin-gantt type (unbuilt dist) — the plugin-view README was among the 43 READMEs it judged. Both are CI's runs; this PR's doc diffs move zero fenced snippets.
  • governed-surface predicate (objectstack scripts/pm/check-governed-merges.mjs --test, all 8 paths) — 0 of 8 path(s) hit the register → NOT governed
  • ablation (Clause-② yes): objectql.zod.ts alone reverted to the base blob, trap-guarded with absolute paths — mutation proven on disk (tombstone line and spec-reference line each 1 → 0; blob 97b7a668 vs HEAD 44e31169); the three pins under it: Test Files 3 failed (3), Tests 37 failed | 100 passed (137) — 34 in the new pin, 2 in object-view-spec-parity (backlog, audit figures), 1 in the ledger (SPEC_DERIVED_PAIRS re-derivation); the controls green; tsc -p tsconfig.test.json exit 2 with the compile-time ledger naming exactly 'objectql.zod.ts#ObjectViewSchema'; restored via git checkout HEAD -- path, blob 44e31169 equals HEAD's, git diff HEAD empty, status clean

Sibling overlap

#7493's dev touches zod-mirror-parity.test.ts at the base.zod.ts#ComponentInputSchema rows and its own header figures; this PR touches only the objectql.zod.ts#ObjectViewSchema rows, the UnmirroredDeclared figures and SPEC_DERIVED_PAIRS. Textual overlap is possible on the header-figure lines; the union is both history sentences plus the re-derived totals, which the objectui#7279 pin checks. The merge queue rebuilds on main; origin/main is merged again when the sibling lands. Left DRAFT with needs:contract-review; no ready flip, no enqueue.

Noted for the seat, out of this card's scope: the NamedListView declaration itself carries about 45 members nothing reads off a named view — a liveness question of its own, not one of this card's ten keys.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s


Generated by Claude Code

…ence) and retire viewTabBar (objectui#7779)

`ObjectViewSchema`'s TypeScript face declared ten keys its Zod mirror never
did (objectui#7279's `UnmirroredDeclared` reading), so a document authoring
any of them passed the validator unexamined through `BaseSchema`'s
passthrough. Maintainer ruling B (2026-09-06): liveness first, then
mirror-or-retire per key.

- objectql.zod.ts: `navigation` / `searchableFields` / `filterableFields` are
  `SpecListViewSchema.shape.*` by reference (identity-pinned);
  `allowCreateView` / `viewActions` are the sibling `ViewSwitcherSchema`
  slots by reference (the renderer forwards both verbatim into the
  `view-switcher` node); `defaultViewType` (the declaration's seven-value
  union) / `defaultListView` / `showViewSwitcher` are local literals after a
  reader census on `plugin-view/src/ObjectView.tsx`; `viewTabBar` is a
  `retirementTombstone()` (zero reads — the tab-bar config is `ViewTabBar`'s
  `config` prop from the host, never a node key)
- objectql.ts: `viewTabBar?: never` with the RETIRED docblock (the #7322 shape)
- `listViews` stays unmirrored on the ruling's own fallback clause, with the
  measurement pinned against the spec: the declaration's `NamedListView`
  (about 52 members, seven read) and the spec's strict `ObjectListViewSchema`
  (requires `columns`, refuses `options`, tuple filters and `default`) are
  incompatible, and the spec value refuses the named views the docs teach
- zod-mirror-parity: the entry shrinks to `listViews`; `ObjectViewSchema`
  joins `SPEC_DERIVED_PAIRS` by a real code reference; header figures
  14 / 96 -> 14 / 87, split 1 / 2 + 13 / 94 -> 2 / 3 + 12 / 84, with the
  history sentences
- object-view-spec-parity: `TS_ONLY_BACKLOG` shrinks to `listViews` +
  `onNavigate`; the audit figures move 11 / 13 -> 20 / 22 with the arithmetic
- new pin object-view-unmirrored-keys-7779: reads derived off disk with
  controls, membership, spec/sibling identity, accept-and-survive plus
  wrong-typed refusal at the key per mirrored key, the tombstone on both
  faces, the `listViews` measurement, neighbour and passthrough controls,
  the two doc tables
- docs: the plugin-view README and plugin-view.mdx import tables no longer
  teach `viewTabBar` as a node key
- changeset: `@object-ui/types` minor, "Breaking for authored metadata"

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3189.4 KB 3191.4 KB
Main entry chunk (gzip) 143.5 KB 350 KB
Entry file index-BS3c0yHp.js
Status PASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 15.67KB 5.75KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 5.13KB 2.35KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 510.60KB 116.20KB
core (index.js) 6.96KB 2.79KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 182.08KB 50.62KB
fields (index.js) 242.44KB 61.25KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 4.28KB 1.75KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.98KB 10.98KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 11.71KB 4.29KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 47.87KB 13.31KB
plugin-charts (index.js) 70.92KB 19.75KB
plugin-chatbot (index.js) 196.19KB 46.37KB
plugin-dashboard (index.js) 132.88KB 34.69KB
plugin-designer (index.js) 212.86KB 43.19KB
plugin-detail (index.js) 250.55KB 64.06KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 132.87KB 32.66KB
plugin-gantt (index.js) 167.26KB 41.00KB
plugin-grid (index.js) 209.29KB 56.78KB
plugin-kanban (index.js) 52.71KB 14.55KB
plugin-list (index.js) 113.76KB 27.75KB
plugin-map (index.js) 20.44KB 6.78KB
plugin-markdown (index.js) 13.93KB 4.81KB
plugin-report (index.js) 43.59KB 11.97KB
plugin-timeline (index.js) 30.40KB 8.76KB
plugin-tree (index.js) 9.20KB 3.19KB
plugin-view (index.js) 85.24KB 20.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 5.41KB 2.34KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 4.93KB 2.24KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 10.35KB 3.60KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.74KB 1.41KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Copy link
Copy Markdown
Contributor

Contract review (clause ②) — PASS — PR #7922 at head 94e7ac47 (Fixes #7779)

Director seat (objectstack #12708, summon #15), session_01TezFG8ZMrNH6n5VTNpPpdH (os-zhuang), 2026-09-06T03:43Z, batch review under the maintainer's 「按批次执行完所有的契约复审」. Tier fuse: get_session this session reads session_context.model = last_served_model = CONTRACT_REVIEW_TIER. Readings from the PR diff (8 files; code in packages/types/src/objectql.ts and zod/objectql.zod.ts), card #7779 + the maintainer ruling 5556357004 (batch 2 of 2026-09-05, 「第二批(4 项,契约形状族) 帮我处理,全部同意」 → option B); dev report 5556615555 read afterwards as cross-check.

Implemented-by: dev subagent of session_01BAZFhALsQsGqxui8sNqM8s (branch claude/issue-7779-object-view-unmirrored-keys)
Reviewed-by: session_01TezFG8ZMrNH6n5VTNpPpdH

Clause ② standing — yes, correctly declared

ObjectViewSchema's Zod mirror gains eight enforced keys (accept set narrows for wrong-typed values) and refuses viewTabBar by name; the TS face retires viewTabBar to ?: never. Published @object-ui/types surface, both faces.

① Derived judgments

# claim reading verdict
1 Ruling B executed nine-for-ten: three spec-modelled keys mirrored by reference to SpecListViewSchema.shape.*; two by reference to the sibling ViewSwitcherSchema slots the renderer forwards into; three local literals after a reader census; viewTabBar retired Diff read: navigation: SpecListViewSchema.shape.navigation, searchableFields / filterableFields likewise; allowCreateView / viewActions: ViewSwitcherSchema.shape.*; defaultViewType seven-value enum (host-composition-only chart/tree excluded per objectui#5321), defaultListView string, showViewSwitcher boolean; viewTabBar: retirementTombstone(...) + ?: never. No local restatement of a spec shape — the drift objectui#4588 keeps paying for is avoided by construction. correct
2 listViews stays in the ledger on the ruling's own fallback clause, with the measurement pinned against the spec (the strict ObjectListViewSchema refuses the named views this package's own docs teach; the local NamedListView would enforce ~45 unread members) Exactly the ruling's stop condition; ⛔ not z.any(). The value-type decision is the maintainer's box, not this review's. correct
3 Reader census on the object-view node renderer with schema.objectName / schema.layout as firing controls; viewTabBar zero reads repo-wide outside @object-ui/types; ViewTabBarConfig reaches the bar only as a host-composed prop (ADR-0053) Derived off disk in the pin. correct
4 Ledger moves: UnmirroredDeclared 14/96 → 14/87; ObjectViewSchema re-derived into SPEC_DERIVED_PAIRS by a real code reference; object-view-spec-parity's shrink-only backlog pin moved by a gate Consistent with the parity-ledger discipline (PR #7776 / #7832 shape). correct
5 52-test pin; ablation 37 red / 100 green across three files with the compile-time ledger naming the entry Discriminating direction. correct
6 Two doc tables corrected (plugin-view README, plugin-view.mdx), zero fenced snippets moved content/docs/releases/ untouched. accepted

② semver

@object-ui/types minor, "Breaking for authored metadata" opening — this repo's fixed-group convention (breaking ships as minor; check-changeset-no-major enforced). Correct.

③ Boundary flags

Evidence and landing

Checks on 94e7ac47: 29 success / 3 skipped / 0 red; mergeable_state: clean; governed-surface predicate 0 of 8 paths. Clearing, same stroke: needs:contract-review off PR #7922 (the card carried none) with provenance; landing from this seat: ready + auto-merge SQUASH.


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 6, 2026 03:46
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 6, 2026
Merged via the queue into main with commit 5b5a5c3 Sep 6, 2026
34 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-7779-object-view-unmirrored-keys branch September 6, 2026 04:02
os-justin pushed a commit that referenced this pull request Sep 6, 2026
…tion lines (objectui#7779 pin)

`packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts` landed on
`main` (PR #7922) one minute after this branch merged its base, so its
`REGISTRATION_TEXT` hard-codes three `plugin-view/src/index.tsx` registration
lines that still carry the `ComponentInput.label` key this PR retires. The pin
asserted a fact this change is the reason is no longer true.

Each expected string is copied off the registration source rather than composed
by hand: only the `label: '…', ` fragment is dropped, every other character is
the line as `packages/plugin-view/src/index.tsx` now reads. The assertion stays
an exact `toContain` over three entries — the pin's intent (the three local
literals are still registered as editable inputs) survives the retirement.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation package: types plugin tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Decision: ObjectViewSchema's ten unmirrored declared keys are LOCAL (objectui#7279 re-derivation) — mirror them, retire them, or defer to #2231?

3 participants